package org.pombo.sqm;

import org.pombo.gtm.Game;
import org.pombo.gtm.Node;
import org.pombo.gtm.Player;
import org.pombo.gtm.Strategy;

class WorstPayoffMeasurer implements StrategyQualityMeasurer {

	private Game game;
	private Player player;

	WorstPayoffMeasurer(Game game, Player player) {
		this.game = game;
		this.player = player;
	}

	public double measureStrategyQuality(Strategy strategy) {
		Node rootNode = this.game.getRootNode();

		ProbabilityCalculatorFactory probCalcFactory = this.getProbabilityCalculatorFactory(strategy);
		NodeProbabilities playerNodeProbabilities = probCalcFactory.on(rootNode).nodeProbabilities(1);
		WorstPayoffCalculatorFactory worstPayoffCalcFactory = this.getWorstPayoffCalculatorFactory(strategy, playerNodeProbabilities);

		return worstPayoffCalcFactory.on(rootNode).worstPayoff();
	}

	private ProbabilityCalculatorFactory getProbabilityCalculatorFactory(Strategy strategy) {
		ProbabilityCalculatorFactory probCalcFactory = new ProbabilityCalculatorFactory(this.player);

		PayoffNodeProbabilityCalculator payoffProbCalculator = new PayoffNodeProbabilityCalculator();
		ChanceNodeProbabilityCalculator chanceProbCalculator = new ChanceNodeProbabilityCalculator(probCalcFactory);
		PlayerNodeProbabilityCalculator playerProbCalculator = new PlayerNodeProbabilityCalculator(probCalcFactory, strategy);
		OpponentNodeProbabilityCalculator opponentProbCalculator = new OpponentNodeProbabilityCalculator(probCalcFactory);

		probCalcFactory.setPayoffNodeCalculator(payoffProbCalculator);
		probCalcFactory.setChanceNodeCalculator(chanceProbCalculator);
		probCalcFactory.setPlayerNodeCalculator(playerProbCalculator);
		probCalcFactory.setOpponentNodeCalculator(opponentProbCalculator);

		return probCalcFactory;
	}

	private WorstPayoffCalculatorFactory getWorstPayoffCalculatorFactory(Strategy strategy, NodeProbabilities nodeProbabilities) {
		WorstPayoffCalculatorFactory worstPayoffCalcFactory = new WorstPayoffCalculatorFactory(this.player);

		PayoffNodeWorstPayoffCalculator payoffNodeWPCalc = new PayoffNodeWorstPayoffCalculator(this.player);
		ChanceNodeWorstPayoffCalculator chanceNodeWPCalc = new ChanceNodeWorstPayoffCalculator(worstPayoffCalcFactory);
		PlayerNodeWorstPayoffCalculator playerNodeWPCalc = new PlayerNodeWorstPayoffCalculator(worstPayoffCalcFactory, strategy);
		OpponentNodeWorstPayoffCalculator opponentNodeWPCalc = new OpponentNodeWorstPayoffCalculator(worstPayoffCalcFactory, nodeProbabilities);

		worstPayoffCalcFactory.setPayoffNodeCalculator(payoffNodeWPCalc);
		worstPayoffCalcFactory.setChanceNodeCalculator(chanceNodeWPCalc);
		worstPayoffCalcFactory.setPlayerNodeCalculator(playerNodeWPCalc);
		worstPayoffCalcFactory.setOpponentNodeCalculator(opponentNodeWPCalc);

		return worstPayoffCalcFactory;
	}
}
